package ru.amse.jsynchro.kernel.task;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import ru.amse.jsynchro.fileSystem.FileSystem;
import ru.amse.jsynchro.kernel.Difference;
import ru.amse.jsynchro.kernel.IDirectoryTree;
import ru.amse.jsynchro.kernel.Operation;
import ru.amse.jsynchro.logging.ILogger;

/**
 * The task supports process of controlling
 * changes in local and remote folders and 
 * automatic synch of them. The task holds
 * local directory tree, which was created 
 * in the last action of comparing local and
 *  remote folders
 * @author miha
 *
 */
public class HistoryTask extends DirectedDelTask {
    private IDirectoryTree oldTree;
    private IDirectoryTree newTree;
    private IDirectoryTree serverTree;
    private List<Difference> localDiffs;
    private List<Difference> serverDiffs;
    private ILogger logger;
    public HistoryTask(ILogger logger) throws IOException {
        super(null, null, null, null, true, logger);
        this.logger = logger;
        
    }
    public List<Difference> analyzeUpload(String newFolder, FileSystem newFS,
            String serverFolder, FileSystem serverFS) throws IOException {
        serverTree = serverFS.getDirectoryTree(serverFolder);
        serverTree.setCompareFileContent(false);
        newTree = newFS.getDirectoryTree(newFolder);
        if (oldTree == null) {
            oldTree = newTree; 
        }
        newTree.setCompareFileContent(false);
//        System.out.println("before compare");
        serverDiffs = newTree.compare(serverTree, false);
//        System.out.println("after compare");
//        System.out.println(serverDiffs.size());
        resolveConflicts(serverDiffs);
        combineAtomic(serverDiffs, newTree, serverTree);
        
        //!!!!! oldTree = newTree; 
        return serverDiffs;
    }
    
    public List<Difference> analyzeRemote(String newFolder, FileSystem newFS,
            String serverFolder, FileSystem serverFS) throws IOException {
        serverTree = serverFS.getDirectoryTree(serverFolder);
        serverTree.setCompareFileContent(false);
        newTree = newFS.getDirectoryTree(newFolder);
        if (oldTree == null) {
            oldTree = newTree; 
        }
        serverDiffs = serverTree.compare(oldTree, false);
        resolveConflicts(serverDiffs);
        combineAtomic(serverDiffs, serverTree, oldTree);
        return serverDiffs;
    }
    
    protected void resolveConflicts(List<Difference> diffs) {
        for (Difference diff: diffs) {
            if (diff.getOperation() == Operation.CONFLICT) {
                diff.setOperation(Operation.ADD);
            }
        }
    }
    
    public boolean analyze(String newFolder, FileSystem newFS, 
                           String serverFolder, FileSystem serverFS) throws IOException {
        logger.info("in task.analyze()");
        newTree = newFS.getDirectoryTree(newFolder);
        if (oldTree != null) {
            newTree.setCompareFileContent(false);
            localDiffs = newTree.compare(oldTree, true);
            logger.info("***** localDiffs ******");
            for (Difference d: localDiffs) {
                logger.info(d.toString());
            }
            logger.info("***** end of localDiffs ******");
            combineAtomic(localDiffs, newTree, oldTree);
//            oldTree = oldTree;
            
        }  else {
            oldTree = newTree;
            localDiffs = new ArrayList<Difference>();
        }
        
        
        serverTree = serverFS.getDirectoryTree(serverFolder);
        serverTree.setCompareFileContent(false);
        serverDiffs = serverTree.compare(oldTree, true);
        combineAtomic(serverDiffs, serverTree, oldTree);
        for (Difference dif: serverDiffs) {
            System.out.println(dif);
        }
        oldTree = newTree;
        return (serverDiffs.size() > 0) || (localDiffs.size() > 0);
    }
    
    protected void combineAtomic(List<Difference> diffs, IDirectoryTree source, IDirectoryTree destination) {
        List<Difference> atomic = new ArrayList<Difference>();
        for (Difference d: diffs) {
            if (d.getOperation() == Operation.ADD) {
                source.addAtomicDiff(d, atomic, false);
            } else {
                destination.addAtomicDiff(d, atomic, true);
            }
        }
        diffs.clear();
        diffs.addAll(atomic);
    }
    
    public void update() {
        applyChanges(serverDiffs, serverTree, oldTree);
    }
    
    public void upload() {
        applyChanges(serverDiffs, newTree, serverTree);
    }
    
    public List<String> getStringDifferences(List<Difference> diffs, IDirectoryTree destination) {
        
        List<String> result = new ArrayList<String>();
        
        for (Difference d: diffs) {
            if (d.getOperation() != Operation.NOTHING) {
                result.add(destination.getPath() + File.separator + d.toString());
            }
        }
        return result;
    }
    
    public void commit() {
//        System.out.println("in commit");
        applyChanges(localDiffs, newTree, serverTree);
    }
}
